﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Net.Sockets;

namespace Mimoza.Transport
{
    /// <summary>
	/// Represents listener socket.	
	/// </summary>
    public class Listener    
    {
        /// <summary>
        /// Delegate for notification about connection creation.	
        /// </summary>
        public delegate void ConnectionCreatedNotifier(Connection connection);

        public Listener(int port)
        {
            CreateSocket();
            Bind(port);
                        
            Common.Logger.Log.Info("Create listener on port - " + port.ToString() + ".");
        }

        public void Close()
        {
            if (m_socket != null)
            {
                Common.Logger.Log.Info("Close port - " + m_port.ToString() + ".");

                m_socket.Close();
            }
        }

        private void CreateSocket()
        {
            m_socket = new Socket(AddressFamily.InterNetwork, 
				                          SocketType.Stream, 
				                          ProtocolType.Tcp);
        }

        private void Bind(int port)
        {
			IPEndPoint ipLocal = new IPEndPoint(IPAddress.Any, port);

            m_socket.Bind(ipLocal);
            m_socket.Listen(port);
            m_port = port;
        }

        public void StartAccept(ConnectionCreatedNotifier notifier)
        {
            m_notifier = notifier;
            StartAsyncAccept();
        }

        public void EndAccept()
        {
            m_notifier = null;
        }
        
        private void StartAsyncAccept()
        {
            m_socket.BeginAccept(new AsyncCallback(OnConnect),null);
        }

        private void OnConnect(IAsyncResult asyncRes)
        {
            Connection conn = null;
            try
            {
                conn = new Connection(m_socket.EndAccept(asyncRes));
            }
            catch(Exception e)
            {
                Common.Logger.Log.Error("OnClientConnect error - '" 
                    + e.Message + "'\n");
                return;
            }

            if (m_notifier != null)
            {
                // notify about created connection
                m_notifier(conn);
            }

            StartAsyncAccept();

            if (conn != null)
            {
                Common.Logger.Log.Trace("OnClientConnect accept connection. Remote location - '" +
                    conn.RemoteAddress + "'\n");
            }
        }

        private Socket m_socket = null;
        private int m_port = 0;
        private ConnectionCreatedNotifier m_notifier;
    }
}
